﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Drawing.Text;

namespace Walson.Windows.Forms
{
    public partial class Battery : Control
    {

        private int _Value = 50;
        public int Value
        {
            get
            {
                return _Value;
            }
            set
            {
                if (_Value != value)
                {
                    if (value > 100)
                        value = 100;

                    _Value = value;
                    DrawBattery();
                    this.Invalidate();
                }
            }
        }


        private int _ThresholdWarnning = 30;
        public int ThresholdWarnning
        {
            get
            {
                return _ThresholdWarnning;
            }
            set
            {
                if (_ThresholdWarnning != value)
                {
                    if (value > 100)
                        value = 100;

                    _ThresholdWarnning = value;
                    DrawBattery();
                    this.Invalidate();
                }
            }
        }

        private int _ThresholdAlarm = 10;
        public int ThresholdAlarm
        {
            get
            {
                return _ThresholdAlarm;
            }
            set
            {
                if (_ThresholdAlarm != value)
                {
                    if (value > 100)
                        value = 100;

                    _ThresholdAlarm = value;
                    DrawBattery();
                    this.Invalidate();
                }
            }
        }

        private Orientation _Orientation = Orientation.Horizontal;
        public Orientation Orientation
        {
            get
            {
                return _Orientation;

            }
            set
            {
                if (_Orientation != value)
                {
                    _Orientation = value;
                    GetBorder();
                    DrawBattery();
                    this.Invalidate();
                }
            }
        }

        private Color _BorderColor = Color.White;
        public Color BorderColor
        {
            get
            {
                return _BorderColor;
            }
            set
            {
                if (_BorderColor != value)
                {
                    _BorderColor = value;
                    DrawBattery();
                    this.Invalidate();
                }
            }
        }

        private Color[] _InnerColorNormal = new Color[] { Color.Green, Color.Green };
        public Color[] InnerColorNormal
        {
            get
            {
                return _InnerColorNormal;
            }
            set
            {
                if (_InnerColorNormal != value)
                {
                    _InnerColorNormal = value;
                    _FullNormalGradientPosition = new float[value.Length];
                    for (int i = 0; i < _FullNormalGradientPosition.Length; i++)
                    {
                        _FullNormalGradientPosition[i] = (float)i / ((float)_FullNormalGradientPosition.Length - 1f);
                    }
                    DrawBattery();
                    this.Invalidate();
                }
            }
        }

        private Color[] _InnerColorWarnning = new Color[] { Color.Yellow, Color.Yellow };
        public Color[] InnerColorWarnning
        {
            get
            {
                return _InnerColorWarnning;
            }
            set
            {
                if (_InnerColorWarnning != value)
                {
                    _InnerColorWarnning = value;
                    _FullWarnningGradientPosition = new float[value.Length];
                    for (int i = 0; i < _FullWarnningGradientPosition.Length; i++)
                    {
                        _FullWarnningGradientPosition[i] = (float)i / ((float)_FullWarnningGradientPosition.Length - 1f);
                    }
                    DrawBattery();
                    this.Invalidate();
                }
            }
        }

        private Color[] _InnerColorAlarm = new Color[] { Color.Red, Color.Red };
        public Color[] InnerColorAlarm
        {
            get
            {
                return _InnerColorAlarm;
            }
            set
            {
                if (_InnerColorAlarm != value)
                {
                    _InnerColorAlarm = value;
                    _FullAlarmGradientPosition = new float[value.Length];
                    for (int i = 0; i < _FullAlarmGradientPosition.Length; i++)
                    {
                        _FullAlarmGradientPosition[i] = (float)i / ((float)_FullAlarmGradientPosition.Length - 1f);
                    }
                    DrawBattery();
                    this.Invalidate();
                }
            }
        }

        private Color[] _EmptyColor = new Color[] { Color.Gray, Color.LightGray };
        public Color[] EmptyColor
        {
            get
            {
                return _EmptyColor;
            }
            set
            {
                if (_EmptyColor != value)
                {
                    _EmptyColor = value;

                    _EmptyGradientPosition = new float[value.Length];
                    for (int i = 1; i < _EmptyGradientPosition.Length; i++)
                    {
                        _EmptyGradientPosition[i] = (float)i / ((float)_EmptyGradientPosition.Length - 1f);
                    }
                    DrawBattery();
                    this.Invalidate();
                }
            }
        }

        private float[] _FullNormalGradientPosition = new float[] { 0f, 1f };


        private float[] _FullWarnningGradientPosition = new float[] { 0f, 1f };


        private float[] _FullAlarmGradientPosition = new float[] { 0f, 1f };


        private float[] _EmptyGradientPosition = new float[] { 0f, 1f };


        private int _CapHeight = 5;
        public int CapHeight
        {
            get
            {
                return _CapHeight;
            }
            set
            {
                if (_CapHeight != value)
                {
                    _CapHeight = value;
                    GetBorder();
                    DrawBattery();
                    this.Invalidate();
                }
            }
        }

//         private Color _BackColor = Color.Transparent;
//         /// <summary>
//         /// 背景色
//         /// </summary>
//         public override Color BackColor
//         {
//             get
//             {
//                 return _BackColor;
//             }
//             set
//             {
//                 if (_BackColor != value)
//                 {
//                     _BackColor = value;
//                     this.Invalidate();
//                 }
//             }
//         }



        private PointF[] _BorderPoints;
        private Bitmap _Battery;



        public Battery()
        {
            InitializeComponent();
            this.DoubleBuffered = true;

            this.SizeChanged += delegate 
            {
                GetBorder();
                DrawBattery();
            };
        }

        private void GetBorder()
        {
            if (_BorderPoints == null)
                _BorderPoints = new PointF[9];

            if (_Orientation == Orientation.Vertical)
            {
                /*
                     2    3
                      +--+
                 0,8  |  | 
                  +---+  +---+  5
                  |   1  4   |
                  |          |
                  |          |
                  |          |
                7 +----------+ 6

                 */

                _BorderPoints[0] = new PointF(0, _CapHeight);
                _BorderPoints[1] = new PointF(this.Width * 0.3f, _CapHeight);
                _BorderPoints[2] = new PointF(this.Width * 0.3f, 1);
                _BorderPoints[3] = new PointF(this.Width * 0.7f, 1);
                _BorderPoints[4] = new PointF(this.Width * 0.7f, _CapHeight);
                _BorderPoints[5] = new PointF(this.Width - 1, _CapHeight);
                _BorderPoints[6] = new PointF(this.Width - 1, this.Height - 1);
                _BorderPoints[7] = new PointF(0, this.Height - 1);
                _BorderPoints[8] = new PointF(0, _CapHeight);
            }
            else
            {
                /*

                0,8              1
                +---------------+
                |               |
                |             2 +--+ 3
                |                  |
                |             5 +--+ 4
                |               |
                +---------------+ 6
                7 
                 */

                _BorderPoints[0] = new PointF(0, 0);
                _BorderPoints[1] = new PointF(this.Width - _CapHeight - 1, 0);
                _BorderPoints[2] = new PointF(this.Width - _CapHeight - 1, this.Height * 0.3f);
                _BorderPoints[3] = new PointF(this.Width - 1, this.Height * 0.3f);
                _BorderPoints[4] = new PointF(this.Width - 1, this.Height * 0.7f);
                _BorderPoints[5] = new PointF(this.Width - _CapHeight - 1, this.Height * 0.7f);
                _BorderPoints[6] = new PointF(this.Width - _CapHeight - 1, this.Height - 1);
                _BorderPoints[7] = new PointF(0, this.Height - 1);
                _BorderPoints[8] = new PointF(0, 0);
            }
        }

        private void DrawBattery()
        {
            if (this.Width == 0 || this.Height == 0)
            {
                _Battery = null;
                return;
            }
            //Bitmap bmp = new Bitmap(this.Width, this.Height);
            _Battery = new Bitmap(this.Width, this.Height);

            using (Graphics g = Graphics.FromImage(_Battery))
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
                g.Clear(Color.Transparent);

                if(_BorderPoints==null)
                {
                    GetBorder();
                }

                if(_Orientation==Orientation.Vertical)
                {
                    /*
                         2    3
                          +--+
                     0,8  |  | 
                      +---+  +---+  5
                      |   1  4   |
                      |          |
                      |          |
                      |          |
                    7 +----------+ 6
                     
                     */

                    // 画电池正极的突起
                    g.FillRectangle(new SolidBrush(Color.FromArgb(64, 64, 64)), _BorderPoints[2].X, _BorderPoints[2].Y, this.Width * 0.4f, _CapHeight);
                    // 高光
                    g.FillRectangle(new SolidBrush(Color.FromArgb(30, 255, 255, 255)), _BorderPoints[2].X+ this.Width * 0.2f, _BorderPoints[2].Y, this.Width * 0.2f, _CapHeight);
                    LinearGradientBrush lgb = new LinearGradientBrush(new Rectangle(0,_CapHeight, this.Width, this.Height), Color.Red, Color.White, 0f);

                    ColorBlend blend = new ColorBlend();

                    // 绘制电池为空的图形
                    blend.Colors = _EmptyColor;

                    blend.Positions = _EmptyGradientPosition;

                    lgb.InterpolationColors = blend;

                    g.FillRectangle(lgb, new RectangleF(0f, _CapHeight, this.Width, this.Height - _CapHeight));

                    // 绘制电池有电的图形

                    if (_Value > ThresholdWarnning)
                    {
                        blend.Positions = _FullNormalGradientPosition;
                        blend.Colors = _InnerColorNormal;
                    }
                    else if (_Value > ThresholdAlarm)
                    {
                        blend.Positions = _FullWarnningGradientPosition;
                        blend.Colors = _InnerColorWarnning;
                    }
                    else
                    {
                        blend.Positions = _FullAlarmGradientPosition;
                        blend.Colors = _InnerColorAlarm;
                    }

                    lgb.InterpolationColors = blend;
                    float h = (this.Height - _CapHeight) * Value / 100f;
                    g.FillRectangle(lgb, 0, this.Height - h, this.Width, h);
                    // 高光
                    g.FillRectangle(new SolidBrush(Color.FromArgb(30, 255, 255, 255)), this.Width / 2, _CapHeight, this.Width / 2, this.Height - _CapHeight);
                    g.DrawLines(new Pen(_BorderColor, 2f), _BorderPoints);
                }
                else
                {
                    /*
                    
                    0,8              1
                    +---------------+
                    |               |
                    |             2 +--+ 3
                    |                  |
                    |             5 +--+ 4
                    |               |
                    +---------------+ 6
                    7 
                     */

                    // 画电池正极的突起
                    g.FillRectangle(new SolidBrush(Color.FromArgb(64, 64, 64)), _BorderPoints[2].X, _BorderPoints[2].Y, _CapHeight, this.Height * 0.4f);
                    // 高光
                    g.FillRectangle(new SolidBrush(Color.FromArgb(30, 255, 255, 255)), _BorderPoints[2].X, _BorderPoints[2].Y + this.Height * 0.2f, _CapHeight, this.Height * 0.2f);

                    //LinearGradientBrush lgb = new LinearGradientBrush(new Rectangle(0, 30, this.Width, this.Height), Color.Red, Color.White, 90f);
                    LinearGradientBrush lgb = new LinearGradientBrush(new Rectangle(0, 0, this.Width - _CapHeight, this.Height), Color.Red, Color.Red, 90);

                    ColorBlend blend = new ColorBlend();

                    // 绘制电池为空的图形
                    blend.Colors = _EmptyColor;

                    blend.Positions = _EmptyGradientPosition;

                    lgb.InterpolationColors = blend;

                    g.FillRectangle(lgb, new RectangleF(0f, 0, this.Width-_CapHeight, this.Height));

                    // 绘制电池有电的图形

                    if (_Value > ThresholdWarnning)
                    {
                        blend.Positions = _FullNormalGradientPosition;
                        blend.Colors = _InnerColorNormal;
                    }
                    else if (_Value > ThresholdAlarm)
                    {
                        blend.Positions = _FullWarnningGradientPosition;
                        blend.Colors = _InnerColorWarnning;
                    }
                    else
                    {
                        blend.Positions = _FullAlarmGradientPosition;
                        blend.Colors = _InnerColorAlarm;
                    }

                    lgb.InterpolationColors = blend;
                    
                    //lgb.RotateTransform(90);
                    g.FillRectangle(lgb, 0, 0, (this.Width - _CapHeight) * Value / 100f, this.Height);
                    // 高光
                    g.FillRectangle(new SolidBrush(Color.FromArgb(30, 255, 255, 255)), 0, this.Height / 2, this.Width - _CapHeight, this.Height / 2);
                    //lgb.ResetTransform();
                    g.DrawLines(new Pen(_BorderColor, 2f), _BorderPoints);
                }
            }
        }

        private Bitmap DrawEmptyBattery(int width, int height)
        {
            if (width == 0 || height == 0)
                return null;

            Bitmap bmp = new Bitmap(width, height);
            {
                using (Graphics g = Graphics.FromImage(bmp))
                {
                    g.SmoothingMode = SmoothingMode.AntiAlias;
                    g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
                    //g.Clear(Color.Transparent);
                    g.Clear(Color.Red);

                    PointF[] borderPoints = new PointF[9];
                    borderPoints[0] = new PointF(0, _CapHeight);
                    borderPoints[1] = new PointF(width / 2 - width * 0.2f, _CapHeight);
                    borderPoints[2] = new PointF(width / 2 - width * 0.2f, 1);
                    borderPoints[3] = new PointF(width / 2 + width * 0.2f, 1);
                    borderPoints[4] = new PointF(width / 2 + width * 0.2f, _CapHeight);
                    borderPoints[5] = new PointF(width - 1, _CapHeight);
                    borderPoints[6] = new PointF(width - 1, height - 1);
                    borderPoints[7] = new PointF(0, height - 1);
                    borderPoints[8] = new PointF(0, _CapHeight);

                    // 画电池正极的突起
                    g.FillRectangle(new SolidBrush(Color.FromArgb(64, 64, 64)), borderPoints[2].X, borderPoints[2].Y, borderPoints[4].X - borderPoints[2].X, borderPoints[4].Y - borderPoints[2].Y);

                    LinearGradientBrush lgb = new LinearGradientBrush(new Rectangle(0, 30, width, height), Color.Red, Color.White, 0f);

                    ColorBlend blend = new ColorBlend(9);

                    // 绘制电池为空的图形
                    blend.Colors = _EmptyColor;

                    blend.Positions = _EmptyGradientPosition;

                    lgb.InterpolationColors = blend;

                    g.FillRectangle(lgb, new RectangleF(0f, _CapHeight, width, height - _CapHeight));

                    // 绘制电池有电的图形

                    if (_Value > ThresholdWarnning)
                    {
                        blend.Positions = _FullNormalGradientPosition;
                        blend.Colors = _InnerColorNormal;
                    }
                    else if (_Value > ThresholdAlarm)
                    {
                        blend.Positions = _FullWarnningGradientPosition;
                        blend.Colors = _InnerColorWarnning;
                    }
                    else
                    {
                        blend.Positions = _FullAlarmGradientPosition;
                        blend.Colors = _InnerColorAlarm;
                    }

                    lgb.InterpolationColors = blend;
                    g.FillRectangle(lgb, new RectangleF(0f, height - (height - _CapHeight) * Value / 100f, width, (height - _CapHeight) * Value / 100f));

                    g.DrawLines(new Pen(_BorderColor, 2f), borderPoints);
                }
            }
            //bmp.Save(@"c:\a.bmp");
            return bmp;
        }

        protected override void OnPaint(PaintEventArgs pe)
        {

            using (Bitmap bmp = new Bitmap(this.Width, this.Height))
            {
                using (Graphics g = Graphics.FromImage(bmp))
                {
                    g.SmoothingMode = SmoothingMode.AntiAlias;
                    g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
                    g.Clear(BackColor);

                    if(_Battery==null)
                    {
                        DrawBattery();
                    }
                    g.DrawImage(_Battery, 0, 0);


                    SizeF fontSize = g.MeasureString(this.Value.ToString() + "%", this.Font);

                    g.DrawString(this.Value.ToString() + "%", this.Font, new SolidBrush(this.ForeColor), (this.Width - fontSize.Width) / 2f, (this.Height - fontSize.Height) / 2f);

                }
                pe.Graphics.DrawImage(bmp, 0, 0);
            }

            base.OnPaint(pe);
        }
    }
}
